import { generate, parser } from '@shaderfrog/glsl-parser';
import { FunctionNode, Program } from '@shaderfrog/glsl-parser/ast';

/**
 * 删除未被使用的 函数、Uniform、属性。
 *
 * @param program
 */
export function removeUnuse(program: Program)
{
    // 是否删除了代码
    let isDelete = false;
    // 删除未使用的函数
    const functionScopeIndex = program.scopes[0].functions;
    const funcNames = Object.keys(functionScopeIndex);
    for (let i = 0; i < funcNames.length; i++)
    {
        const funcName = funcNames[i];
        if (funcName === 'main') continue; // 保留 main 函数

        // 是否被使用
        let isUse = false;
        const funcDeclarations: FunctionNode[] = [];
        //
        const functionOverloadIndex = functionScopeIndex[funcName];
        for (const signature in functionOverloadIndex)
        {
            const functionOverloadDefinition = functionOverloadIndex[signature];
            funcDeclarations.push(functionOverloadDefinition.declaration);
            if (functionOverloadDefinition.references.length > 1)
            {
                isUse = true;
            }
        }
        if (!isUse)
        {
            // 从全局范围删除
            delete functionScopeIndex[funcName];

            // 删除函数范围
            program.scopes = program.scopes.filter((v) => v.name !== funcName);

            // 删除源码
            program.program = program.program.filter((v) => !funcDeclarations.includes(v as any));

            //
            isDelete = true;
        }
    }

    // 删除未使用的 unifrom
    const scopeIndex = program.scopes[0].bindings;
    const bindingNames = Object.keys(scopeIndex);
    for (let i = 0; i < bindingNames.length; i++)
    {
        const bindingName = bindingNames[i];
        const scopeEntry = scopeIndex[bindingName];
        // 跳过 UBO
        if (scopeEntry.declaration.type === 'interface_declarator') continue;
        if (scopeEntry.references.length === 1)
        {
            // 从全局范围删除
            delete scopeIndex[bindingName];

            // 删除源码
            program.program = program.program.filter((v) =>
            {
                if (v.type !== 'declaration_statement') return true;
                if (v.declaration.type !== 'declarator_list') return true;
                if (v.declaration.declarations.length === 0) return true;

                return v.declaration.declarations[0].identifier.identifier !== bindingName;
            });

            //
            isDelete = true;
        }
    }

    // 删除代码后可能会把原本被引用的函数或变量成为未使用
    if (isDelete && program.program.length > 0)
    {
        // 从语法树还原为代码。
        const newCode = generate(program);
        //
        program = parser.parse(newCode);

        program = removeUnuse(program);
    }

    return program;
}
